﻿///////////////////////////////////////////////////////////////////////////////
// File:        Client.cc
// Author:      671643387@qq.com
// Description:
///////////////////////////////////////////////////////////////////////////////


#include <memory>

#include "Summary.hpp"
#include "Client.hpp"
using namespace nio::net;

#define BYTE_SEND   0x10

Client::Client(nio::net::EventLoop& loop)
: id_(0)
, state_(READY)
, sock_(INVALID_SOCKET)
, loop_(loop)
, buff_()
, buffSize_ (0)
, buffLength_(0)
, closeFN_()
{

}

Client::~Client()
{

}

bool Client::open(std::string addr, int port, unsigned int bufSize, std::string message)
{
    assert(message.length() <= bufSize);

    buff_.reset(new char[bufSize]);
    if (!buff_)
        return false;
    buffSize_ = bufSize;

    memset(&buff_[0], BYTE_SEND, bufSize);
    buffLength_ = buffSize_;

    memcpy(&buff_[0], &message[0], message.length());

    if (!sock_.open(AF_INET, SOCK_STREAM))
        return false;

    struct sockaddr_in saddr;
    memset(&saddr, 0, sizeof(saddr));

    saddr.sin_family = AF_INET;
#if defined(__WINDOWS__)
    saddr.sin_addr.S_un.S_addr = ::inet_addr(addr.c_str());
#elif defined(__LINUX__)
    saddr.sin_addr.s_addr = ::inet_addr(addr.c_str());
#endif
    saddr.sin_port = ::htons(u_short(port));

    if (!sock_.connect((const struct sockaddr*)&saddr, sizeof(saddr)))
        return false;

    if (!sock_.setNonblocking(true))
        return false;

    if (!loop_.getReactor()->addSource(sock_.getSOCKET(), Reactor::RE_ALL, this))
        return false;

    state_ = RUNNING;
    return true;
}

void Client::handleInput()
{
    if (state_ != RUNNING)
        return;

    int bytsRead = sock_.read(&buff_[0], buffSize_);
    if (bytsRead == SOCKET_ERROR)
    {
        close();
        return;
    } 
    else if (bytsRead != SOCKET_ERROR_WOULDBLOCK)
    {
        gSummary.inc_RcvPackets();
        gSummary.inc_Packets();
        gSummary.add_Bytes((unsigned long long)bytsRead);
        buffLength_ = bytsRead;
    }
}

void Client::handleOutput()
{
    if (state_ != RUNNING)
        return;

    if (buffLength_ == 0)
        return;

    int bytsWrite = sock_.write(&buff_[0], buffLength_);
    if (bytsWrite == SOCKET_ERROR)
    {
        close();
        return;
    }
    else if (bytsWrite != SOCKET_ERROR_WOULDBLOCK)
    {
        gSummary.inc_SndPackets();
        gSummary.inc_Packets();
        gSummary.add_Bytes((unsigned long long)bytsWrite);
        buffLength_ = 0;
    }
}

void Client::handleError()
{
    if (state_ != RUNNING)
        return;

    close();
}

void Client::handleHeartbeat()
{

}